home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Periodicals / develop / develop 6 code / Chernoff Faces / Faces.c next >
Encoding:
Text File  |  1991-04-03  |  6.7 KB  |  247 lines  |  [TEXT/KAHL]

  1. /*
  2. *
  3. *
  4. *    Faces.c, by Dave Johnson, 3/91.
  5. *
  6. *    Based on Clifford Pickover's Chernoff face routine, in his book "Computers, Pattern, Chaos,
  7. *    and Beauty."
  8. *
  9. *
  10. *    The face is specified by an array of ten byte values ranging from -127 to 127. Here's how
  11. *    the parameters map to facial features (there's no rhyme or reason here, I just used the 
  12. *    same set that Pickover did):
  13. *
  14. *        0 head eccentricity
  15. *        1 eye eccentricity
  16. *        2 pupil size
  17. *        3 eyebrow slope
  18. *        4 nose size
  19. *        5 mouth vert. offset
  20. *        6 eye spacing
  21. *        7 eye size
  22. *        8 mouth width
  23. *        9 mouth "openness"
  24. *
  25. *
  26. *
  27. */
  28.  
  29. /* prototypes for the Face routines */
  30. void         CenterRectOverPoint(Rect*, Point);
  31. Point         GetCenter(Rect *theRect);
  32. int         ScaleChar(char param, int max);
  33. pascal void Face(Rect *rect, char params[]);
  34.  
  35. /*-------------------------------------------------------------------------
  36. CenterRectOverPoint()             Centers theRect over thePt...
  37. --------------------------------------------------------------------------*/
  38. void CenterRectOverPoint(Rect *theRect, Point thePt)
  39. {
  40.     /* First home theRect... */
  41.     OffsetRect(theRect, -theRect->left, -theRect->top);
  42.     
  43.     /* ...then center it over thePt */
  44.     OffsetRect(theRect, thePt.h - (theRect->right / 2), thePt.v - (theRect->bottom / 2));
  45. }
  46.  
  47. /*-------------------------------------------------------------------------
  48. GetCenter()             Returns the center of theRect
  49. --------------------------------------------------------------------------*/
  50. Point GetCenter(Rect *theRect)
  51. {
  52.     Point        pt;
  53.         
  54.     pt.h = theRect->left + ((theRect->right - theRect->left) / 2);
  55.     pt.v = theRect->top + ((theRect->bottom - theRect->top) / 2);
  56.     return(pt);
  57. }
  58.  
  59. /*-------------------------------------------------------------------------
  60. ScaleChar()    Scales param to a range of + or - max, returns the scaled value.
  61.             param is assumed to be between -127 and 127.
  62. --------------------------------------------------------------------------*/
  63. int ScaleChar(char param, int max)
  64. {
  65.     return ((long)param * max) / 127;
  66. }
  67.  
  68. /*-------------------------------------------------------------------------
  69. Face()             Draws a Chernoff face, scaled to bounds, in the current port
  70. --------------------------------------------------------------------------*/
  71. pascal void
  72. Face(Rect *bounds, char params[])
  73. {
  74.     Rect        rect, temprect;
  75.     int            x1, x2, y1, y2, xunit, yunit, temp;
  76.     Point        ctr, eyectr;
  77.     PenState    oldpen;
  78.  
  79.     /*
  80.     * Set up
  81.     */
  82.     
  83.     /* These are our basic units in x and y directions */
  84.     xunit = (bounds->right - bounds->left) / 8;    
  85.     yunit  = (bounds->bottom - bounds->top) / 8;
  86.     
  87.     /* The center of the face */
  88.     ctr = GetCenter(bounds);                
  89.  
  90.     /* Adjust the pen size */
  91.     GetPenState(&oldpen);
  92.     PenNormal();
  93.     x1 = xunit / 10;
  94.     if(x1 < 1)
  95.         x1 = 1;
  96.     y1 = yunit / 10;
  97.     if(y1 < 1)
  98.         y1 = 1;
  99.     PenSize(x1, y1);
  100.     EraseRect(bounds);
  101.  
  102.     /*
  103.     * Draw the Head
  104.     */
  105.     
  106.     /* Inset by one unit so there is room to squish around */
  107.     rect = *bounds;
  108.     InsetRect(&rect, xunit, yunit);
  109.     
  110.     /* Now add eccentricity (params[0], positive is taller) , and draw it */
  111.     InsetRect(&rect, ScaleChar(params[0], xunit / 2), ScaleChar(-params[0], yunit / 2));
  112.     FrameOval(&rect);
  113.     
  114.     /*
  115.     * Draw the Eyes
  116.     */
  117.     
  118.     /* Set up the default eye rect */
  119.     SetRect(&rect, 0, 0, (5 * xunit) / 4, (5 * yunit) / 4);
  120.     
  121.     /* Change the size (param[7], positive is bigger) */
  122.     InsetRect(&rect, ScaleChar(-params[7], xunit / 4), ScaleChar(-params[7], yunit / 4));
  123.     
  124.     /* Add eccentricity (param[1], positive is taller) */
  125.     InsetRect(&rect, ScaleChar(params[1], xunit / 4), ScaleChar(-params[1], yunit / 4));
  126.     
  127.     /* Set location (params[6] is eye spacing, positive is wider), and draw
  128.         the eyes.  Also draw the pupils, while we're here. */
  129.     
  130.     temp = ScaleChar(params[6], xunit / 2);
  131.     CenterRectOverPoint(&rect, ctr);
  132.     temprect = rect;    /* save for other eye */
  133.     OffsetRect(&rect, -(xunit + temp), -((2 * yunit) / 3));
  134.     FrameOval(&rect);
  135.     
  136.     /* Draw the pupil, params[2] is diameter, bigger is bigger. 
  137.         We want a minimum of a 1 pixel dot: no empty eyes */
  138.     
  139.     /* Convert params[2] to a positive number from 0 to 127 */
  140.     x1 = (params[2] + 127) / 2;
  141.     
  142.     /* Scale in x and y directions, min of 1 */    
  143.     y1 = ScaleChar(x1, yunit / 3);
  144.      if(y1 < 1) y1 = 1;
  145.     x1 = ScaleChar(x1, xunit / 3);
  146.      if(x1 < 1) x1 = 1;
  147.     
  148.     /* Get the center of the eye rect */
  149.     eyectr = GetCenter(&rect);
  150.     
  151.     /* Set up the rect and draw it */
  152.     SetRect(&rect, 0, 0, 0, 0);
  153.     InsetRect(&rect, -x1, -y1);
  154.     CenterRectOverPoint(&rect, eyectr);
  155.     PaintOval(&rect);
  156.     
  157.     /* Other eye... */
  158.     rect = temprect;
  159.     OffsetRect(&rect, xunit + temp, -((2 * yunit) / 3));
  160.     FrameOval(&rect);
  161.  
  162.     /* Pupil... */
  163.     eyectr = GetCenter(&rect);
  164.     SetRect(&rect, 0, 0, 0, 0);
  165.     InsetRect(&rect, -x1, -y1);
  166.     CenterRectOverPoint(&rect, eyectr);
  167.     PaintOval(&rect);
  168.     
  169.     /*
  170.     * Eyebrows
  171.     */
  172.     
  173.     /* params[3] is slope, positive slopes down to the outside */
  174.     temp = ScaleChar(params[3], yunit / 2);
  175.     y1 = y2 = ctr.v - (yunit + (2 * yunit) / 3);
  176.     y1 += temp;
  177.     y2 -= temp;
  178.     MoveTo(ctr.h - (3 * xunit) / 2, y1);
  179.     LineTo(ctr.h - xunit / 2, y2);    
  180.     MoveTo(ctr.h + (3 * xunit) / 2, y1);
  181.     LineTo(ctr.h + xunit / 2, y2);
  182.     
  183.     /*
  184.     * Nose
  185.     */
  186.     
  187.     /* params[4] is length, positive is bigger */
  188.     y1 = yunit + (yunit / 3) + ScaleChar(params[4], yunit / 3);
  189.     MoveTo(ctr.h, ctr.v - (yunit / 3));
  190.     Line(xunit / 2, y1);
  191.     Line(-xunit, 0);
  192.     
  193.     /*
  194.     * Mouth
  195.     */
  196.     
  197.     /* params[8] is width, positive is wider */
  198.     temp = ScaleChar(params[8], xunit / 2);
  199.     y1 = ctr.v + (2 * yunit);            /* the neutral position, vertically */
  200.     x1 = xunit + temp;                    /* the horizontal offset from center */
  201.     
  202.     /* Get the points for the lips */
  203.     temp = ScaleChar(params[5], yunit / 3);    /* offset for first lip */
  204.     
  205.     /* For lip 2, scale it */
  206.     y2 = ScaleChar(params[9], yunit / 3);    /* offset for the second lip (relative to first lip) */
  207.     y2 += temp;
  208.     
  209.     /* Draw the first lip */
  210.     if(temp > 0)                        /* if positive, use the bottom (smile) */
  211.     {
  212.         SetRect(&rect, ctr.h - x1, y1 - temp, ctr.h + x1, y1 + temp);
  213.          FrameArc(&rect, 90, 180);
  214.     }
  215.     else if(temp < 0)                    /* if negative, use the top (frown) */
  216.     {
  217.         SetRect(&rect, ctr.h - x1, y1 + temp, ctr.h + x1, y1 - temp);
  218.          FrameArc(&rect, -90, 180);
  219.     }
  220.     else                                /* if neutral, just draw a line */
  221.     {
  222.         MoveTo(ctr.h - x1, y1);
  223.         LineTo(ctr.h + x1 - (xunit / 10), y1);    /* subtract the pen width on the right */
  224.     }
  225.     
  226.     /* Now the second lip */
  227.     temp = y2;
  228.     if(temp > 0)                        /* if positive, use the bottom (smile) */
  229.     {
  230.         SetRect(&rect, ctr.h - x1, y1 - temp, ctr.h + x1, y1 + temp);
  231.          FrameArc(&rect, 90, 180);
  232.     }
  233.     else if(temp < 0)                    /* if negative, use the top (frown) */
  234.     {
  235.         SetRect(&rect, ctr.h - x1, y1 + temp, ctr.h + x1, y1 - temp);
  236.          FrameArc(&rect, -90, 180);
  237.     }
  238.     else                                /* if neutral, just draw a line */
  239.     {
  240.         MoveTo(ctr.h - x1, y1);
  241.         LineTo(ctr.h + x1 - (xunit / 10), y1);    /* subtract the pen width on the right */
  242.     }
  243.     
  244.     /* All Done! restore the pen and return */
  245.     SetPenState(&oldpen);
  246. }
  247.